﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Configuration;
using TicketsPhone.Domain.Entities;
using TicketsPhone.Domain.Access;
using TicketsPhone.Domain.Utils;


namespace TicketsPhone.Service
{
    partial class AsignacionTurnos : ServiceBase
    {
        public AsignacionTurnos()
        {
            //System.Diagnostics.EventLog.WriteEntry("TicketsPhone", "Iniciando el servicio");
            InitializeComponent();
        }

        TurnoRepositorio _turno = new TurnoRepositorio();
        SucursalRepositorio _sucursal = new SucursalRepositorio();
        UsuarioRepositorio _usuario = new UsuarioRepositorio();
        System.Timers.Timer timerTurnos;


        #region Metodos
        private void CargarTimer()
        {
            //System.Diagnostics.EventLog.WriteEntry("TicketsPhone", "Cargar Timer");
            int segundos = Convert.ToInt32(ConfigurationManager.AppSettings["segundosIntervalo"]);
            timerTurnos = new System.Timers.Timer();
            timerTurnos.Interval = segundos * 1000;
            timerTurnos.Elapsed +=new System.Timers.ElapsedEventHandler(timerTurnos_Elapsed);
            timerTurnos.Enabled = true;
            timerTurnos.Start();
        }


        /// <summary>
        /// Valida si el horario de la solicitud del turno está disponible o no
        /// </summary>
        /// <param name="horario">Datos del horario en el que se solicita el turno</param>
        /// <returns></returns>
        public void ProcesarSolicitudes()
        {
            //System.Diagnostics.EventLog.WriteEntry("TicketsPhone", "ProcesarSolicitudes");
            EstadoTurno nuevoEstado = EstadoTurno.Solicitado;

            //procesa los primeros 20 turnos
            List<Turno> turnosSolicitados = _turno.ObtenerTurnosSolicitados().Skip(0).Take(Convert.ToInt32(ConfigurationManager.AppSettings["procesadosPorTurno"])).ToList();
            
            MensajeSMS sms = new MensajeSMS();

            foreach (Turno turno in turnosSolicitados)
            {
                
                int turnosSimultaneos = 0;
                int cajerosActivos = 0;
                List<Horario> listaHorarios = new List<Horario>();

                //si la hora de solicitud es mayor a la actual realiza las validaciones
                if (turno.HoraInicio.EsMayor(new Hora(DateTime.Now)))
                {
                    _turno.Objeto = turno;

                    Horario horario = new Horario();
                    horario.HoraInicio = turno.HoraInicio;
                    horario.HoraFin = turno.HoraFin;
                    horario.Sucursal.IdSucursal = turno.IdSucursal.Value;
                    horario.Dia = turno.FechaTurno.Value.DayOfWeek;

                    turnosSimultaneos = _turno.ContarTurnosSimultaneos();
                    cajerosActivos = _sucursal.ObtenerCajerosActivos(horario);

                    GuardarLog(string.Format("Turno:({4}-{0}-{1}) simultaneos:{2} cajeros activos:{3}", horario.HoraInicio, horario.HoraFin, turnosSimultaneos, cajerosActivos, horario.Dia));
                }

                //Si los turnos solcitados son menores  a los cajeros activos en determinada hora puede asignar el turno
                if (turnosSimultaneos < cajerosActivos)
                {
                    //actualiza el turno a aceptado y envia mensaje
                    nuevoEstado = EstadoTurno.Aceptado;

                    sms.Mensaje = string.Format("El turno {0} ha sido aceptado. Clave de acceso es {1}", turno.IdTurno, turno.Codigo);
                }
                else
                {
                    //actualizaa el turno a rechazado, busca opciones de hora y envia mensaje
                    nuevoEstado = EstadoTurno.Negado;
                    //busca turnos disponibles
                    listaHorarios = BuscarTurnosDisponibles(turno);

                    StringBuilder str = new StringBuilder();
                    str.Append("No hay disponibilidad.");

                    if (listaHorarios.Count > 0)
                        str.Append("Si hay en:");

                    foreach (Horario hora in listaHorarios)
                    {
                        str.AppendFormat(hora.ToString("dd-hh"));
                    }

                    sms.Mensaje = str.ToString();
                }

                sms.Numero = _usuario.Cargar(turno.Usuario.IdUsuario).Email;

                //envia el mensaje de texto
                EviarMensaje(sms, turno.IdTurno.Value);
                
                //Cambia el estado del turno
                _turno.EditarEstadoTurno(turno.IdTurno.Value, nuevoEstado);

            }
        }

        private bool EviarMensaje(MensajeSMS sms, int idTurno)
        {
            
            if (Convert.ToBoolean(ConfigurationManager.AppSettings["enviarSMS"]))
            {
                //Realiza el envío del SMS
                WsSMS.WS_SendSMSClient ws = new WsSMS.WS_SendSMSClient();
                RespuestaSMS respuestaSMS = null;

                try
                {
                    respuestaSMS = new RespuestaSMS(ws.EnviarSMS(sms.Numero, sms.Mensaje));
                    //respuestaSMS = new RespuestaSMS("<respuesta mensajeEnviado='true' error='' />");
                }
                catch (Exception e)
                {
                    LogErroresRepositorio.GuardarLog(e, "Enviando SMS - " + respuestaSMS);
                }

                return true;
            }
            else
            {
                //Si no está activado el envìo de SMS deja en cola el envìo del mensaje
                AlertaRepositorio _alerta = new AlertaRepositorio();
                _alerta.Crear(idTurno, sms.Mensaje);
                return false;
            }
        }

        /// <summary>
        /// Busca turnos disponibles en las siguientes horas
        /// </summary>
        public List<Horario> BuscarTurnosDisponibles(Turno turno)
        {
            TurnoRepositorio _turno = new TurnoRepositorio();

            turno.HoraFin.AgregarMinutos(5);
            turno.HoraInicio.AgregarMinutos(5);
            _turno.Objeto = turno;

            int encontrados = 0;
            int intentos = 0;
            int maximoIntentos = 20;

            Horario horario = new Horario();
            horario.HoraInicio = turno.HoraInicio;
            horario.HoraFin = turno.HoraFin;
            horario.Sucursal.IdSucursal = turno.IdSucursal.Value;
            horario.Dia = turno.FechaTurno.Value.DayOfWeek;

            //listado de horarios disponibles
            List<Horario> listaHorarios = new List<Horario>();

            //intenta buscar los siguientes 3 turnos disponibles en el dia
            while (encontrados < 3)
            {

                

                if (intentos == maximoIntentos)
                    break;

                //si el turno consultado está disponible lo separa
                if (_turno.ContarTurnosSimultaneos() < _sucursal.ObtenerCajerosActivos(horario))
                {
                    encontrados++;
                    //Horario horarioNuevo = new Horario();
                    //horarioNuevo.HoraInicio = horario.HoraInicio;
                    //horarioNuevo.HoraFin = horario.HoraFin;
                    listaHorarios.Add(horario);
                    //Console.WriteLine("--------->Horario:{0} hasta {1}", horario.HoraInicio.ToString(), horario.HoraFin.ToString());
                    GuardarLog(string.Format("--------->Horario:{0} hasta {1}", horario.HoraInicio.ToString(), horario.HoraFin.ToString()));
                }

                horario.HoraFin = horario.HoraFin.AgregarMinutos(5);
                horario.HoraInicio = horario.HoraInicio.AgregarMinutos(5);

                intentos++;
            }

            return listaHorarios;
        }

        private void GuardarLog(string texto)
        {
            Utilidades.Utilidades.EscribirFichero(ConfigurationManager.AppSettings["rutaLog"], string.Format("{0}\t{1}", DateTime.Now, texto));
        }

        

        #endregion


        #region Eventos


        private void timerTurnos_Tick(object sender, EventArgs e)
        {
            //System.Diagnostics.EventLog.WriteEntry("TicketsPhone", "Primer Tick");
            ProcesarSolicitudes();
        }

        

        protected override void OnStart(string[] args)
        {
            // TODO: agregar código aquí para iniciar el servicio.
            //System.Diagnostics.EventLog.WriteEntry("TicketsPhone", "OnStart");
            CargarTimer();
        }

        protected override void OnStop()
        {
            // TODO: agregar código aquí para realizar cualquier anulación necesaria para detener el servicio.
            //System.Diagnostics.EventLog.WriteEntry("TicketsPhone", "OnStop");
            timerTurnos.Stop();
        }

        void timerTurnos_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            try
            {
                ProcesarSolicitudes();
            }
            catch (Exception ex)
            {
                //System.Diagnostics.EventLog.WriteEntry("TicketsPhone", "Error Procesando Solicitudes"+ex.Message);
            }
        }

        #endregion


        
    }
}
